package cn.moefly.common.utils;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Optional;

/**
 * 用于处理一些通用的线程池创建和维护工作
 * Used to handle some general thread pool creation and maintenance work
 */
public abstract class ThreadPoolUtils {


    /**
     * 通过给定的settingMap数据，解析创建线程池
     * Create a thread pool by parsing the given settingMap data
     *
     * @param settingMap will parsing into {@link ThreadPoolSetting}
     * @param defaultPoorNamePrefix be used if the setting not set threadNamePrefix
     * @return
     */
    public static ThreadPoolTaskExecutor ofSettingMap(Map<String,?> settingMap, String defaultPoorNamePrefix){
        ThreadPoolSetting setting = new ThreadPoolSetting();
        populateBean(settingMap,setting);
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        Optional.ofNullable(setting.corePoolSize).ifPresent(executor::setCorePoolSize);
        Optional.ofNullable(setting.maxPoolSize).ifPresent(executor::setMaxPoolSize);
        Optional.ofNullable(setting.keepaliveSeconds).ifPresent(executor::setKeepAliveSeconds);
        executor.setThreadNamePrefix(Optional.ofNullable(setting.threadNamePrefix)
                .orElse(Optional.ofNullable(defaultPoorNamePrefix).orElse(System.nanoTime() + "-pool-")));
        executor.initialize();
        return executor;
    }


    private static void populateBean(Map map, Object bean){
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            var fieldName = field.getName();
            var o = map.get(fieldName);
            if (o != null){
                field.setAccessible(true);
                try {
                    field.set(bean,o);
                } catch (IllegalAccessException e) {
                    throw new IllegalArgumentException("incorrect thread pool configuration");
                }
            }
        }
    }

    private static class ThreadPoolSetting{
        Integer corePoolSize;
        Integer maxPoolSize;
        Integer keepaliveSeconds;
        String threadNamePrefix;
    }
}
